/*
 * BackgammonEvaluation200105474_200092928.java
 * CMPT 310 - Assignment 2 - Part 3
 * The following file represents a program written in Java
 *  programming language. The file describes a class that is used to
 *  evaluate a BackgammonBoard
 */

package bkgm;

/**
 *
 * @author: Andriy Baranskyy, Egor Chalubeyeu
 * email: abaransk@sfu.ca and egorc@sfu.ca
 */
public class BackgammonEvaluation200105474_200092928 extends Evaluation 
{
    /** Creates a new instance of BackgammonEvaluation200105474_200092928 */
    public BackgammonEvaluation200105474_200092928() 
    {
	MAX_SCORE = (BackgammonBoard.CHECKERS_PER_PLAYER+Dice.DIE_MAX)*BackgammonBoard.NUM_POINTS*BackgammonBoard.NUM_POINTS;
	MIN_SCORE = -MAX_SCORE; 
    }
    //This function returns the board evaluation score given the board and the number of player from whose 
    //perspective we are evaluating the board
    public float boardScore(BackgammonBoard b, int player) 
    {
        //decide which strategy to adopt
        int tempEval=evaluateCheckers(b,player);
        boolean blitzGame=false;
        if(b.on_bar[1-player]>0)
        {
            //it's a blitz game and we can try blocking the other player and run away:
            tempEval+=blitzGameEvaluation(b,player);
            blitzGame=true;
        }
        if (tempEval<=2*b.NUM_POINTS*b.NUM_POINTS && !blitzGame)
            //it's a priming game
        {
            tempEval+=primingGameEvaluation(b,player);
        }
        //else it's a runaaway game
        //finally, penalise for 1-checker points
        tempEval-=penaliseForOneCheckerPoints(b,player);
        return (float)tempEval;
    }
    //The following function checks the number of single checkers that can be hit
    //by our opponent
    private int penaliseForOneCheckerPoints(BackgammonBoard b, int player)
    {
        int numberOfSingleCheckers=0;
        if(player==1)
        {
            int i=b.NUM_POINTS-1;
            //skip checkers that cannot be threatened
            while(i>=0 && b.board[i]>=0)
                i--;
            for(int y=0;y<i;y++)
            {
                if(b.board[i]==1)
                    numberOfSingleCheckers++;
            }
        }
        else
        {
            int i=0;
            //skip checkers that cannot be threatened
            while(i<b.NUM_POINTS && b.board[i]<=0)
                i++;
            for(int y=(i+1);y<b.NUM_POINTS;y++)
            {
                if(b.board[i]==-1)
                    numberOfSingleCheckers++;
            }
        }
        return numberOfSingleCheckers;
    }
    //The following function adds a bonus to blocking an opponent's
    //checker on the base
    private int blitzGameEvaluation(BackgammonBoard b, int player)
    {
        int k=0;
        int i=(1-player)*(b.NUM_POINTS-1);
        while((b.board[i]*player+player-1)>(player+b.board[i]*(1-player))&&(k<7))
        {
            k++;
            i+=2*player-1;
        }
        return k*b.NUM_POINTS;
    }
    //The following function gives bonus for having a straight row
    //of points of at least two checkers per point near the
    //opponent's home
    private int primingGameEvaluation(BackgammonBoard b, int player)
    {
        int atLeastTwoCheckersPerPoint=0;
        int maxTwoCheckersPerPoint=0;
        for(int i=(player+13*(1-player));i<(11*player+23*(1-player));i++)
        {
            if((player*b.board[i]-1+player)>(player+(1-player)*b.board[i]))
                atLeastTwoCheckersPerPoint++;
            else
            {
                if(atLeastTwoCheckersPerPoint>maxTwoCheckersPerPoint)
                    maxTwoCheckersPerPoint=atLeastTwoCheckersPerPoint;
                atLeastTwoCheckersPerPoint=0;
            }
        }
        if(atLeastTwoCheckersPerPoint>maxTwoCheckersPerPoint)
            maxTwoCheckersPerPoint=atLeastTwoCheckersPerPoint;
        
        return maxTwoCheckersPerPoint*b.NUM_POINTS;
    }
    //This function is used to evaluate the board in the following way:
    //It weights your checkers more if they are closer to your home,
    //giving you the maximum weight for the checkers that are at home
    //and penalises you for the opponent's checkers that are close
    //to his or her home. It penalises you for the checkers you
    //have on bar and rewards you for the opponents checkers on bar
    private int evaluateCheckers(BackgammonBoard b, int player)
    {
        int value=0;
        for (int i=0;i<b.NUM_POINTS;i++)
        {
            if(b.board[i]>0)
                value= value+player*b.board[i]*i-(1-player)*b.board[i]*i;
            else
                value= value-player*b.board[i]*(b.NUM_POINTS-i-1)+(1-player)*b.board[i]*(b.NUM_POINTS-i-1);
        }
        value+=b.in_home[player]*b.NUM_POINTS;
        value-=b.in_home[1-player]*b.NUM_POINTS;
        value-=b.on_bar[player]*b.NUM_POINTS;
        value+=b.on_bar[1-player]*b.NUM_POINTS*b.NUM_POINTS;
        return value;
    }
}
